/**
 * Copyright (C) 2018-2022
 * All rights reserved, Designed By www.yixiang.co
 * 注意：
 * 本软件为www.yixiang.co开发研制
 */
package com.avic.modules.system.service.impl;

import com.avic.common.service.impl.BaseServiceImpl;
import com.avic.common.utils.QueryHelpPlus;
import com.avic.dozer.service.IGenerator;
import com.avic.exception.BadRequestException;
import com.avic.modules.log.domain.vo.LogEnumeration;
import com.avic.modules.log.domain.vo.LogVo;
import com.avic.modules.log.service.LogsService;
import com.avic.modules.log.utils.ContrastObjUtil;
import com.avic.modules.system.domain.Dept;
import com.avic.modules.system.domain.Job;
import com.avic.modules.system.domain.RolesDepts;
import com.avic.modules.system.domain.vo.DeptVo;
import com.avic.modules.system.service.DeptService;
import com.avic.modules.system.service.dto.DeptDto;
import com.avic.modules.system.service.dto.DeptQueryCriteria;
import com.avic.modules.system.service.mapper.DeptMapper;
import com.avic.modules.system.service.mapper.JobMapper;
import com.avic.modules.system.service.mapper.RolesDeptsMapper;
import com.avic.utils.FileUtil;
import com.avic.utils.ValidationUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhangzikang
 * @date 2022-08-14
 */
@Service
@AllArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, Dept> implements DeptService {

    private final IGenerator generator;

    private final DeptMapper deptMapper;

    private final JobMapper jobMapper;

    private final RolesDeptsMapper rolesDeptsMapper;

    private final LogsService logsService;

    private static final String ENTITY_NAME = "dept";

    @Override
    public Map<String, Object> queryAll(DeptQueryCriteria criteria, Pageable pageable) {
        getPage(pageable);
        PageInfo<Dept> page = new PageInfo<>(queryAll(criteria));
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content", generator.convert(page.getList(), DeptDto.class));
        map.put("totalElements", page.getTotal());
        return map;
    }


    @Override
    public List<Dept> queryAll(DeptQueryCriteria criteria) {
        return baseMapper.selectList(QueryHelpPlus.getPredicate(Dept.class, criteria));
    }


    @Override
    public void download(List<DeptDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        long sum = 1;
        for (DeptDto dept : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("序号", sum);
            map.put("名称", dept.getName());
            Dept dept1 = deptMapper.selectById(dept.getPid());
            if (dept1 != null) {
                map.put("上级部门", dept1.getName());
            } else {
                map.put("上级部门", "");
            }
            if (dept.getEnabled()) {
                map.put("状态", "启用");
            } else {
                map.put("状态", "禁用");
            }
            if(dept.getCreateTime()!=null){
                String s = dept.getCreateTime().toString();
                String substring = s.substring(0, s.length() - 2);
                map.put("创建日期", substring);
            } else {
                map.put("创建日期", "");
            }

            sum++;
            list.add(map);
        }
        // 创建操作日志信息
        LogVo logVo = new LogVo();
        String name = "[导出]了" + "[部门信息]";
        logVo.setBehavior(name);
        logVo.setAction(LogEnumeration.LEADING_OUT.getMessage());
        logsService.save(logVo);

        FileUtil.downloadExcel(list, response);
    }

    /**
     * 根据PID查询
     *
     * @param pid /
     * @return /
     */
    @Override
    public List<Dept> findByPid(long pid) {
        DeptQueryCriteria criteria = new DeptQueryCriteria();
        criteria.setPid(pid);
        return baseMapper.selectList(QueryHelpPlus.getPredicate(Dept.class, criteria));
    }

    /**
     * 构建树形数据
     *
     * @param deptDtos 原始数据
     * @return /
     */
    @Override
    public Object buildTree(List<DeptDto> deptDtos) {
        Set<DeptDto> trees = new LinkedHashSet<>();
        Set<DeptDto> depts = new LinkedHashSet<>();
        List<String> deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList());
        boolean isChild;
        DeptQueryCriteria criteria = new DeptQueryCriteria();
        List<Dept> deptList = this.queryAll(criteria);
        for (DeptDto deptDto : deptDtos) {
            isChild = false;
            if ("0".equals(deptDto.getPid().toString())) {
                trees.add(deptDto);
            }
            for (DeptDto it : deptDtos) {
                if (it.getPid().equals(deptDto.getId())) {
                    isChild = true;
                    if (deptDto.getChildren() == null) {
                        deptDto.setChildren(new ArrayList<>());
                    }
                    deptDto.getChildren().add(it);
                }
            }
            if (isChild) {
                depts.add(deptDto);
                for (Dept dept : deptList) {
                    if (dept.getId().equals(deptDto.getPid()) && !deptNames.contains(dept.getName())) {
                        depts.add(deptDto);
                    }
                }
            }
        }

        if (CollectionUtils.isEmpty(trees)) {
            trees = depts;
        }

        Integer totalElements = deptDtos.size();

        Map<String, Object> map = new HashMap<>(2);
        map.put("totalElements", totalElements);
        map.put("content", CollectionUtils.isEmpty(trees) ? deptDtos : trees);
        return map;
    }

    /**
     *  查询所有子集
     * @param total
     * @return /
     */
    @Override
    public List<Long> queryTree(List<Long> total,Long pid) {
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.eq("pid",pid);
        List<Dept> depts = deptMapper.selectList(wrapper);
        List<Long> longs = recursionById(depts, total);

        return longs;
    }

    /**
     * 查询所有父级
     * @param total
     * @param id
     * @return
     */
    @Override
    public List<Long> queryPid(List<Long> total, Long id) {
        total.add(id);
        Dept dept = deptMapper.selectById(id);
        if(dept.getPid()!=0){
            queryPid(total,dept.getPid());
        }

        return total;
    }

    /**
     * 递归查询部门
     * @param menuList
     * @param id
     * @return
     */
    @Override
    public List<Long> recursionById(List<Dept> menuList, List<Long> id) {
        for (Dept menu1 : menuList) {
            id.add(menu1.getId());
            QueryWrapper<Dept> wrapper = new QueryWrapper<>();
            wrapper.eq("pid", menu1.getId());
            List<Dept> menus = deptMapper.selectList(wrapper);
            if (menus != null && menus.size() != 0) {
                recursionById(menus, id);
            }
        }
        return id;
    }

    /**
     * 删除部门
     *
     * @param deptIds
     */
    @Override
    public void delDepts(List<Long> deptIds) {
        Long jobCount = jobMapper.selectCount(Wrappers.<Job>lambdaQuery().in(Job::getDeptId, deptIds));
        Long roleCount = rolesDeptsMapper.selectCount(Wrappers.<RolesDepts>lambdaQuery()
                .in(RolesDepts::getDeptId, deptIds));
        Long deptCount = deptMapper.selectCount(Wrappers.<Dept>lambdaQuery().in(Dept::getPid, deptIds));
        if (jobCount > 0) {
            throw new BadRequestException("所选部门中存在与岗位关联，请取消关联后再试");
        }
        if (roleCount > 0) {
            throw new BadRequestException("所选部门中存在与角色关联，请取消关联后再试");
        }
        if (deptCount > 0) {
            throw new BadRequestException("所选部门中存在子部门, 请取消关联后再试");
        }

        //创建操作日志
        List<String> js = new ArrayList<>();
        for(Long dept:deptIds){
            Dept dept1 = deptMapper.selectById(dept);
            if(dept1!=null){
                js.add(dept1.getName());
            }
        }

        String name = "[删除]了"+ js.toString() + "部门信息";
        LogVo logVo = new LogVo();
        logVo.setAction(LogEnumeration.Delete.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);
        this.removeByIds(deptIds);
    }

    /**
     * 添加部门
     * @param resources
     */
    @Override
    public void add(Dept resources) {
        if (resources.getId() != null) {
            throw new BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID");
        }

        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.eq("name",resources.getName());
        List<Dept> depts = deptMapper.selectList(wrapper);
        List<Long> total = new ArrayList<>();
        List<Long> longs1 = queryPid(total, resources.getPid());
        for(Dept dept:depts){
            List<Long> total2 = new ArrayList<>();
            List<Long> longs = queryPid(total2, dept.getPid());
            if(longs1.size()==longs.size()){
                boolean whether = true;
                for(Long sum:longs1){
                    if(longs.contains(sum)){
                        whether = true;
                    } else {
                        whether = false;
                        break;
                    }
                }
                if(whether){
                    throw new BadRequestException("同级别相同部门名称不可重复");
                }

            }

        }
        deptMapper.insert(resources);
        // 创建操作日志
        String name = "[添加]了"+ " [" + resources.getName()+ "] " +"部门信息";
        LogVo logVo = new LogVo();
        logVo.setAction(LogEnumeration.Add_TO.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);
        resources.setCreateTime(new Timestamp(System.currentTimeMillis()));
    }

    @Override
    public void updateDept(Dept resources) {
        if (resources.getId().equals(resources.getPid())) {
            throw new BadRequestException("上级不能为自己");
        }
        Dept dept = getOne(new LambdaQueryWrapper<Dept>()
                .eq(Dept::getId, resources.getId()));
        ValidationUtil.isNull(dept.getId(), "Dept", "id", resources.getId());
        List<Long> total = new ArrayList<>();
        List<Long> longs1 = queryTree(total, resources.getId());
        if(longs1.contains(resources.getPid())){
            throw new BadRequestException("上级不能为自己，子集");
        }

        // 查看是否有同级别部门名称
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        wrapper.eq("name",resources.getName());
        List<Dept> depts2 = deptMapper.selectList(wrapper);
        List<Long> total2 = new ArrayList<>();
        List<Long> longs2= queryPid(total2, resources.getPid());
        for(Dept dept2:depts2){
            List<Long> total3 = new ArrayList<>();
            List<Long> longs = queryPid(total3, dept2.getPid());
            if(longs2.size()==longs.size() && dept2.getId()!=resources.getId()){
                boolean whether = true;
                for(Long sum:longs2){
                    if(longs.contains(sum)){
                        whether = true;
                    } else {
                        whether = false;
                        break;
                    }
                }
                if(whether){
                    throw new BadRequestException("同级别部门名称不可重复");
                }
            }

        }

        // 关闭上级，所有子级都关闭
        DeptQueryCriteria deptQueryCriteria = new DeptQueryCriteria();
        deptQueryCriteria.setId(resources.getId());
        List<Dept> depts = queryAll(deptQueryCriteria);
        List<Long> pid = new ArrayList<>();
        List<Long> longs = recursionById(depts, pid);
        for(Long lo:longs){
            Dept dept1 = deptMapper.selectById(lo);
            dept1.setEnabled(resources.getEnabled());
            dept1.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            saveOrUpdate(dept1);
        }

        // 修改前的数据
        DeptVo deptVo = new DeptVo();
        deptVo.setName(dept.getName());
        Boolean enabled = dept.getEnabled();
        if(enabled){
            deptVo.setEnabled("启用");
        } else {
            deptVo.setEnabled("禁用");
        }
        Dept dept3 = deptMapper.selectById(dept.getPid());
        deptVo.setPidName(dept3!=null?dept3.getName():null);

        // 修改后的数据
        DeptVo deptSmall = new DeptVo();
        deptSmall.setName(resources.getName());
        Boolean enabled1 = resources.getEnabled();
        if(enabled1){
            deptSmall.setEnabled("启用");
        }else {
            deptSmall.setEnabled("禁用");
        }

        Dept dept4 = deptMapper.selectById(resources.getPid());
        deptSmall.setPidName(dept4!=null?dept4.getName():null);

        // 创建操作日志
        String s = ContrastObjUtil.comparObj(deptSmall,deptVo);
        String name = "[修改]了"+ " [" + dept.getName() + "] " +"部门信息";
        LogVo logVo = new LogVo();
        logVo.setInformation(s);
        logVo.setAction(LogEnumeration.MODIFY.getMessage());
        logVo.setBehavior(name);
        logsService.save(logVo);

        resources.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        resources.setId(dept.getId());
        deptMapper.updateById(resources);
    }

    /**
     * 根据角色ID查询
     *
     * @param id /
     * @return /
     */
    @Override
    public Set<Dept> findByRoleIds(Long id) {
        return deptMapper.findDeptByRoleId(id);
    }
}
